/**
 * 非公平锁，只保留了加锁的核心逻辑
 *
 * @Author yangSen
 * @date 2022-05-06 11:15
 */
static final class NonfairSync extends Sync {
  private static final long serialVersionUID = 7316153563782823691L;

  /**
   * 等待队列的尾部，惰性初始化。修改仅通过方法enq添加新的等待节点。
   */
  private transient volatile Node tail;

  /**
   * 同步状态。使用了 volatile 关键字
   * <p>
   * volatile 在操作系统中有两个作用
   * <p>
   * 1.保证可见性，不保证原⼦性
   * （1）当写⼀个volatile变量时，JMM会把该线程本地内存中的变量强制刷新到主内存中去；
   * （2）这个写会操作会导致其他线程中的volatile变量缓存⽆效。
   *
   * <p>
   * 2.禁⽌指令重排
   * 重排序是指编译器和处理器为了优化程序性能⽽对指令序列进⾏排序的⼀种⼿段。
   * 比如 a=1; b=a;  执行顺序，可能会被优化成 b=a; a=1;
   * volatile 能禁止指令重排
   */
  private volatile int state;

  /**
   * 中断线程
   */
  static void selfInterrupt() {
    Thread.currentThread().interrupt();
  }

  /**
   * 检查和更新获取失败的节点的状态。如果线程阻塞，返回true。
   * 这是所有获取回路的主要信号控制。要求pred == node.prev。
   */
  private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
    int ws = pred.waitStatus;
    //该节点已经设置了请求释放的状态，以便安全停止
    if (ws == Node.SIGNAL) {
      return true;
    }
    if (ws > 0) {
      /*
       *前任被取消了。跳过之前的版本并指示重试。
       */
      do {
        node.prev = pred = pred.prev;
      } while (pred.waitStatus > 0);
      pred.next = node;
    } else {
      /*
       * waitStatus必须为0或PROPAGATE。
       * 表示需要信号，但先别停车。来电者将需要重试，以确保它不能获得之前停车。
       */
      compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
    }
    return false;
  }

  /**
   * 可重入锁加锁过程
   */
  final void lock() {
    // 底层使用 native 修饰，调用操作系统的 CAS 算法进行判断是否拿到了锁
    if (compareAndSetState(0, 1)) {
      // 当前线程设置为独占线程
      setExclusiveOwnerThread(Thread.currentThread());
    } else {
      acquire(1);
    }
  }

  public final void acquire(int arg) {
    // 没有抢到锁   &&
    if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) {
      selfInterrupt();
    }
  }

  /**
   * 尝试获取锁
   *
   * @param acquires 1
   */
  protected final boolean tryAcquire(int acquires) {
    return nonfairTryAcquire(acquires);
  }

  /**
   * 尝试获取锁 可重入
   *
   * @param acquires
   * @return
   */
  final boolean nonfairTryAcquire(int acquires) {
    // 获取当前线程
    final Thread current = Thread.currentThread();
    // 获取同步状态
    int c = getState();
    // 表示当前的锁没有被占有
    if (c == 0) {
      // cas算法抢锁
      if (compareAndSetState(0, acquires)) {
        // 抢到之后设置为 独占
        setExclusiveOwnerThread(current);
        return true;
      }
      //不是0，表示线程被持有，判断一下这个线程是不是自己
    } else if (current == getExclusiveOwnerThread()) {
      // 锁的重入次数 + 1
      int nextc = c + acquires;
      if (nextc < 0) {
        throw new Error("Maximum lock count exceeded");
      }
      // 重新设置同步状态
      setState(nextc);
      return true;
    }
    return false;
  }

  /**
   * 返回同步状态的当前值。
   * 该操作的内存语义为{@code volatile} read。
   */
  protected final int getState() {
    return state;
  }

  /**
   * 排队获取锁
   * <p>
   * ^_^ 看不动了，多线程调试不动
   *
   * @param node
   * @param arg
   * @return
   */
  final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
      boolean interrupted = false;
      for (; ; ) {
        final Node p = node.predecessor();
        if (p == head && tryAcquire(arg)) {
          setHead(node);
          p.next = null; // help GC
          failed = false;
          return interrupted;
        }
        if (shouldParkAfterFailedAcquire(p, node) &&
          parkAndCheckInterrupt()) {
          interrupted = true;
        }
      }
    } finally {
      if (failed) {
        cancelAcquire(node);
      }
    }
  }

  /**
   * 添加到队列中
   *
   * @param mode
   * @return
   */
  private Node addWaiter(Node mode) {
    // 创建一个节点
    Node node = new Node(Thread.currentThread(), mode);
    // 将队列中最后一个节点进行赋值
    Node pred = tail;
    // 不是空表示不是第一个元素，队列里面有元素
    if (pred != null) {
      // 将原节点放到新节点的前面
      node.prev = pred;
      // 设置新节点为尾节点 ， 底层C++实现
      if (compareAndSetTail(pred, node)) {
        // 将新节点放到原节点的后面  形成双向队列
        pred.next = node;
        return node;
      }
    }
    // 尾节点为空,说明队列还未初始化,需要初始化head节点并入队新节点
    enq(node);
    return node;
  }

  /**
   * @param node
   * @return
   */
  private Node enq(final Node node) {
    for (; ; ) {
      Node t = tail;
      if (t == null) { // Must initialize
        // 如果tail为空,则新建一个head节点,并且tail指向head
        if (compareAndSetHead(new Node())) {
          tail = head;
        }
      } else {
        // 不是空的，就将节点设置为后一个
        node.prev = t;
        if (compareAndSetTail(t, node)) {
          t.next = node;
          return t;
        }
      }
    }
  }

}



